# -*- coding: utf-8 -*-
"""
    Created by huangyi at 2020/9/2.
    Copyright (c) 2013-present, Xiamen Dianchu Technology Co.,Ltd.
    Description:
    Changelog: all notable changes to this file will be documented
"""
import inspect

from app.aop.processor import BeanProcessor, BaseProcessor, ProcessorContext
from app.utils.bean_utils import BeanUtils


class BeanProxy:
    """
    代理类
    """

    def __init__(self, bean_instance, fn_find_processor=lambda bean_name: []):
        self.bean_instance = bean_instance
        self.fn_find_processor = fn_find_processor

    def __getattr__(self, item):
        bean_item = getattr(self.bean_instance, item)
        if bean_item and inspect.ismethod(bean_item):
            # 方法包装类
            bean_name = BeanUtils.get_instance_full_class_name(self.bean_instance)
            return BeanFuncWrap(bean_name, bean_item, self.fn_find_processor)
        return bean_item


class BeanFuncWrap:

    def __init__(self, bean_name, func, fn_find_processor):
        self.func = func
        self.bean_name = bean_name
        self.fn_find_processor = fn_find_processor

    def __call__(self, *args, **kwargs):
        processor_list = self.fn_find_processor(self.bean_name)
        last = None
        head = None
        func_bean_processor = BeanProcessor("", self.func)
        if processor_list:
            # 有匹配到处理器
            for index, processor in enumerate(processor_list):
                if not head:
                    head = processor
                if not last:
                    last = processor
                else:
                    last.set_next(processor)
                    last = processor

            last.set_next(func_bean_processor)
        else:
            # 无处理器，则直接包装原始方法
            head = func_bean_processor
        ctx = ProcessorContext()
        ctx.class_name = self.bean_name
        ctx.method_name = self.func.__name__
        return head.invoke(ctx, *args, **kwargs)


class A:
    def hello(self, name):
        return name


class TestProcessor(BaseProcessor):

    def invoke(self, ctx, *args, **kwargs):
        print("前置动作")
        result = self.get_next().invoke(ctx, *args, **kwargs)
        print(f"test:{result}")
        print("后置动作")
        return result


if __name__ == '__main__':
    a = A()
    proxy = BeanProxy(a, fn_find_processor=lambda bean_name: [TestProcessor("aaaa")])
    name = proxy.hello("hahaha")
    print(f"name={name}")
